/*
 * RSAccessor.cpp
 *
 *  Created on: 2010/03/16
 *      Author: alexandre
 */

#include "RSAccessor.h"
#include "RSDocument.h"
#include "RSDataSource.h"
#include "RSParam.h"

namespace Realsphere {

    RSAccessor::RSAccessor ( Realsphere::RSDataSource* rDataSource, int rOffset, int rStride )
    {
        SetSource ( rDataSource );
        SetOffset ( rOffset, false );
        SetStride ( rStride, false);
    }

    RSAccessor::~RSAccessor ()
    {
        mSource = NULL;
    }

    unsigned int RSAccessor::Count() const {
        return mCount;
    }

    unsigned int RSAccessor::Offset () const {
        return mOffset;
    }

    QString RSAccessor::Source () const {

        if ( mSource != NULL )
            return mSource->URI();

        return QString::null;
    }

    unsigned int RSAccessor::Stride () const {
        return mStride;
    }

    RSDataSource* RSAccessor::SourceElement () const {
        return mSource;
    }

    RSParam* RSAccessor::GetParam ( const QString& rName ) const {

        RSParamsIterator iterator = RSParamsIterator ( mParams );

        while ( iterator.hasNext() ) {

            RSParam* param = iterator.next();

            if ( param->Name() == rName || param->ScopeId() == rName )
                return param;
        }

        return NULL;
    }

    RSParam* RSAccessor::GetParam ( unsigned int rIndex ) const {
        return mParams[rIndex];
    }

    int RSAccessor::IndexOf ( RSParam* rParam ) const {
        return mParams.indexOf ( rParam );
    }

    unsigned int RSAccessor::ParamsSize () const {
        return mParams.size();
    }

    RSParams RSAccessor::Params() const {
        return mParams;
    }

    RSParamsIterator RSAccessor::ParamsIterator () const {
        return RSParamsIterator(mParams);
    }

    void RSAccessor::Reset() {
        if ( mSource == NULL )
            mPosition = NULL;

        mPosition = mSource->DataPointer() + mOffset;
    }

    void RSAccessor::First () {
        Reset();
    }

    void RSAccessor::Next () {
        mPosition += mDataStride;
    }

    void RSAccessor::Prev () {
        mPosition -= mDataStride;
    }

    void RSAccessor::Last () {

        if ( mSource == NULL )
            mPosition = NULL;

        mPosition = mSource->DataPointer() + mSource->SizeOf() - mDataStride;
    }

    bool RSAccessor::IsRootElement () const {
        return false;
    }

    bool RSAccessor::HasNext() const {
        bool result = ( mSource != NULL );

        if ( result ) {

            result &= ( mPosition >= mSource->DataPointer() + mOffset );
            result &= ( mPosition < mSource->DataPointer()+mSource->SizeOf() );
        }

        return result;
    }

    RSError RSAccessor::SetOffset ( unsigned int rOffset, bool rEmit ) {

        mOffset = 0;

        if ( mSource == NULL )
            return RS_DATA_SOURCE_NOT_DEFINED;

        if ( rOffset > mSource->SizeOf()-mDataStride )
            return RS_OFFSET_OUT_OF_BOUNDS;

        mOffset = rOffset;

        if ( rEmit )
            emit OffsetChanged ( mOffset );

        return RS_NO_ERROR;
    }

    RSError RSAccessor::SetSource ( const QString& rSourceId, bool rEmit ) {

        if ( RootElement () == NULL )
            return RS_ROOT_ELEMENT_NOT_DEFINED;

        if ( !RootElement ()->InstanceOf ( RS_DOCUMENT_CLASS ) )
            return RS_UNIMPLEMENTED;

        RSDocument* document = RSDocumentCast ( RootElement() );
        RSDataSource* source = document->GetDataSource ( rSourceId );

        if ( source == NULL )
            return RS_DATA_SOURCE_NOT_DEFINED;

        return SetSource( source, rEmit );
    }

    RSError RSAccessor::SetSource ( RSDataSource* rSource, bool rEmit ) {
        mSource = rSource;
        if ( rEmit )
            emit SourceChanged ( mSource );
        return RS_NO_ERROR;
    }

    RSError RSAccessor::SetStride ( unsigned int rStride, bool rEmit ) {
        // TODO: Implement RSAccessor::SetStride
        return RS_NO_ERROR;
    }

    RSError RSAccessor::AddParam ( RSParam* rParam ) {
        RSError error = AddChildElement ( rParam );
        return error;
    }

    RSError RSAccessor::RemoveParam ( RSParam* rParam ) {
        RSError error = RemoveChildElement ( rParam );
        return error;
    }

    RSError RSAccessor::RemoveParam ( unsigned int rIndex ) {
        RSParam* param = GetParam ( rIndex );
        RSError error = RemoveParam ( param );
        return error;
    }

    RSError RSAccessor::BeforeAddChildElement ( RSElement* rChild ) {

        RSError error = RSElement::BeforeAddChildElement ( rChild );

        if ( error == RS_INVALID_ELEMENT ) {

            if ( rChild->InstanceOf ( RS_PARAM_CLASS ) ) {
                error = RS_NO_ERROR;
            }
        }

        return error;
    }

    bool RSAccessor::AfterAddChildElement ( RSElement* rChild ) {

        bool handled = RSElement::AfterAddChildElement ( rChild );

        if ( !handled ) {
            if ( rChild->InstanceOf ( RS_PARAM_CLASS ) ) {

                RSParam* param = RSParamCast ( rChild );
                mParams.append ( param );
                handled = true;

                emit ParamAdded ( param );
            }
        }

        return handled;
    }

    bool RSAccessor::AfterRemoveChildElement ( RSElement* rChild ) {

        bool handled = RSElement::AfterRemoveChildElement ( rChild );

        if ( !handled ) {
            if ( rChild->InstanceOf ( RS_PARAM_CLASS ) ) {

                RSParam* param = RSParamCast ( rChild );
                int param_index = mParams.indexOf ( param );
                mParams.removeAt ( param_index );
                handled = true;

                emit ParamRemoved ( param );
            }
        }

        return handled;
    }
}
